Skip to content

Add @Nullsafe(Nullsafe.Mode.LOCAL) to clean interfaces and classes#55568

Open
Nehgupta-1203 wants to merge 1 commit intofacebook:mainfrom
Nehgupta-1203:export-D93118745
Open

Add @Nullsafe(Nullsafe.Mode.LOCAL) to clean interfaces and classes#55568
Nehgupta-1203 wants to merge 1 commit intofacebook:mainfrom
Nehgupta-1203:export-D93118745

Conversation

@Nehgupta-1203
Copy link

Summary:
Add Nullsafe(Nullsafe.Mode.LOCAL) annotation to 10 un-annotated Java interfaces and classes across imagepipeline-base, drawee, and drawee-backends modules. These files require no NULLSAFE_FIXME suppressions — all null contracts are already correct. This is a compile-time annotation for Infer static analysis with zero runtime effect.

Files: QualityInfo, HasImageMetadata, ImageInfo (imagepipeline-base); DraweeHierarchy, SettableDraweeHierarchy, DraweeController, SimpleDraweeControllerBuilder, ControllerViewportVisibilityListener, GenericDraweeHierarchy (drawee); ImageOriginListener (drawee-backends). Also adds infer-annotations dep to drawee/interfaces BUCK.

Context

What is Nullsafe?

Nullsafe is a Meta annotation that enables static null checking via https://fbinfer.com/, Meta's static analysis tool. When you annotate a class
with Nullsafe, Infer analyzes the code at compile time (not runtime) and flags any place where a null value could sneak in and cause a crash.

Without Nullsafe, Infer ignores null issues in that class. With it, every field, parameter, and return value is assumed non-null by default unless
explicitly marked Nullable.

What does Nullsafe.Mode.LOCAL mean?

There are different strictness levels:
┌────────┬─────────────────────────────────────────────────────────────────────────────────────────────┐
│ Mode │ What it checks │
├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
│ LOCAL │ Only checks code within this class. Trusts that other classes return correct values. │
├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
│ STRICT │ Checks this class AND requires all dependencies to also be Nullsafe. Much harder to adopt. │
└────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘
LOCAL is the safe starting point — it catches bugs in the annotated class without requiring the entire dependency tree to be annotated first.

Java-Kotlin Interop and Platform Types

When Kotlin calls unannotated Java code, Kotlin treats return types as platform types (shown as Type!). This means Kotlin doesn't know if it's
nullable or not, and lets you treat it either way:

// Java: public String getName() { ... } (no annotation)
// Kotlin sees: String! (platform type — could be null or non-null)

val name: String = controller.name // Kotlin allows this (treats as non-null)
val name: String? = controller.name // Kotlin also allows this (treats as nullable)

Once we add Nullsafe to the Java class, unannotated types become strictly non-null, and Nullable-annotated types become strictly nullable:

Safety

These changes are compile-time only. Nullsafe and Nullable are annotation-only — they produce zero bytecode changes, zero runtime overhead, and
don't change any actual behavior. They just make the compiler and static analysis catch null bugs earlier.

Reviewed By: cortinico

Differential Revision: D93118745

Summary:
Add Nullsafe(Nullsafe.Mode.LOCAL) annotation to 10 un-annotated Java interfaces and classes across imagepipeline-base, drawee, and drawee-backends modules. These files require no NULLSAFE_FIXME suppressions — all null contracts are already correct. This is a compile-time annotation for Infer static analysis with zero runtime effect.

Files: QualityInfo, HasImageMetadata, ImageInfo (imagepipeline-base); DraweeHierarchy, SettableDraweeHierarchy, DraweeController, SimpleDraweeControllerBuilder, ControllerViewportVisibilityListener, GenericDraweeHierarchy (drawee); ImageOriginListener (drawee-backends). Also adds infer-annotations dep to drawee/interfaces BUCK.

**Context**

What is Nullsafe?

  Nullsafe is a Meta annotation that enables static null checking via https://fbinfer.com/, Meta's static analysis tool. When you annotate a class
  with Nullsafe, Infer analyzes the code at compile time (not runtime) and flags any place where a null value could sneak in and cause a crash.

  Without Nullsafe, Infer ignores null issues in that class. With it, every field, parameter, and return value is assumed non-null by default unless
   explicitly marked Nullable.

  What does Nullsafe.Mode.LOCAL mean?

  There are different strictness levels:
  ┌────────┬─────────────────────────────────────────────────────────────────────────────────────────────┐
  │  Mode  │                                       What it checks                                        │
  ├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
  │ LOCAL  │ Only checks code within this class. Trusts that other classes return correct values.        │
  ├────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
  │ STRICT │ Checks this class AND requires all dependencies to also be Nullsafe. Much harder to adopt. │
  └────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘
  LOCAL is the safe starting point — it catches bugs in the annotated class without requiring the entire dependency tree to be annotated first.

 **Java-Kotlin Interop and Platform Types**

  When Kotlin calls unannotated Java code, Kotlin treats return types as platform types (shown as Type!). This means Kotlin doesn't know if it's
  nullable or not, and lets you treat it either way:

  // Java: public String getName() { ... }  (no annotation)
  // Kotlin sees: String!  (platform type — could be null or non-null)

  val name: String = controller.name      // Kotlin allows this (treats as non-null)
  val name: String? = controller.name     // Kotlin also allows this (treats as nullable)

  Once we add Nullsafe to the Java class, unannotated types become strictly non-null, and Nullable-annotated types become strictly nullable:


 Safety

  These changes are compile-time only. Nullsafe and Nullable are annotation-only — they produce zero bytecode changes, zero runtime overhead, and
  don't change any actual behavior. They just make the compiler and static analysis catch null bugs earlier.

Reviewed By: cortinico

Differential Revision: D93118745
@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Feb 16, 2026
Copy link
Contributor

@cortinico cortinico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

Copy link
Contributor

@cortinico cortinico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants